package settings

import (
	"errors"
	"fmt"
	"gitee.com/zackeus/go-boot/freeswitch/mod/xmlcurl"
	"github.com/beevik/etree"
)

type (
	Option func(xml *Xml) error

	Xml struct {
		doc     *etree.Document
		include *etree.Element
	}
)

func New(opts ...Option) (xmlcurl.XmlConf, error) {
	xml := &Xml{
		doc: etree.NewDocument(),
	}
	xml.doc.CreateProcInst("xml", `version="1.0" encoding="UTF-8"`)
	include := xml.doc.CreateElement("include")
	xml.include = include

	for _, opt := range opts {
		if err := opt(xml); err != nil {
			return nil, err
		}
	}
	return xml, nil
}

func WithValue(key string, value string) Option {
	return func(x *Xml) error {
		process := x.include.CreateElement("X-PRE-PROCESS")
		process.CreateAttr("cmd", "set")
		process.CreateAttr("data", fmt.Sprintf("%s=%s", key, value))
		return nil
	}
}

func (x *Xml) BodyElement() *etree.Element {
	return x.include
}

func (x *Xml) MarshalToXml() ([]byte, error) {
	x.doc.Indent(1)
	return x.doc.WriteToBytes()
}

func (x *Xml) UnMarshalFromString(v string) error {
	if x.doc == nil {
		x.doc = etree.NewDocument()
	}
	if err := x.doc.ReadFromString(v); err != nil {
		return err
	}

	include := x.doc.FindElement("./include")
	if include == nil {
		return errors.New("the element include is nil")
	}
	x.include = include

	return nil
}

func (x *Xml) WriteToFile(path string) error {
	x.doc.Indent(1)
	return x.doc.WriteToFile(path)
}
